#include "Server.h"


#define READ_LEN 10000



Server::Server()
{
	this->_emp = new Empacter();
	this->_cnt = new Network::Host();
	ThreadPool::InitThreadPool(100);
	this->_octIn = 0;
	this->_octOut = 0;
	this->_clientListNbAcces = 0;
	this->_mtxClientListModification = new Mutex();
	this->_mtxClientListBrowse = new Mutex();
}

void	Server::AcceptClient(void* server)
{
	Server*	s = reinterpret_cast<Server*>(server);
	int id = 0;
	unsigned int size;
	Client *clt;
	info_select	*inf;

	while (true)
	{
		Network::Connection* cnt;
		if (s->_cnt->Accept(&cnt) == 0)
		{
			clt = new Client(id++, cnt);
			s->AddClient(clt);
			size = sizeof(int);
			clt->GetConnection()->SendData((char*)&id, &size);
			ThreadPool::Request *rqt = new ThreadPool::Request();
			rqt->function = &Server::SelectReceive;
			rqt->autoFree = true;
			inf = new Server::info_select();
			inf->client = clt;
			inf->server = s;
			rqt->parameters = inf;
			ThreadPool::GetThreadPool()->AddRequest(rqt);
		}
	}
}

void Server::SelectReceive(void* infoSelect)
{
	info_select*	inf = reinterpret_cast<info_select*>(infoSelect);
	unsigned int	len;
	char			buff[READ_LEN];
	Header			head;
	void			*packet;
	unsigned int				size;
	timeval			tmR;

	while (true)
	{
		len = READ_LEN;
		tmR.tv_sec = 1;
		tmR.tv_usec = 0;
		if (inf->client->GetConnection()->ReceiveData(buff, &len, &tmR) == 0)
		{
			if (len > 0)
			{
				inf->server->_octIn += len;
				inf->client->GetBuffer()->Write(buff, len);
				size = inf->client->GetBuffer()->Size();
				while (inf->server->GetEmpacter()->Desempact(inf->client->GetBuffer()->Read(inf->client->GetBuffer()->Size(), false), size, &head))
				{
					packet = inf->client->GetBuffer()->Read(size);
					if (head.base->type == AUDIO)
					{
						inf->server->_mtxClientListModification->Lock();
						if (!inf->server->_mtxClientListBrowse->IsLock())
							inf->server->_mtxClientListBrowse->Lock();
						inf->server->_mtxClientListModification->Unlock();
						inf->server->_clientListNbAcces++;
						std::list<Client*>::iterator it = inf->server->GetClient()->begin();
						std::list<Client*>::iterator end = inf->server->GetClient()->end();
						for(;it != end; ++it)
						{
							if ((*it)->GetId() != inf->client->GetId())
							{
								if ((*it)->SendBuffer(packet, size) == 0)
									inf->server->_octOut += size;
							}
						}
						inf->server->_clientListNbAcces--;
						if (!inf->server->_clientListNbAcces)
							inf->server->_mtxClientListBrowse->Unlock();
					}
					size = inf->client->GetBuffer()->Size();
				}
			}
		}
		else
			break;
	}
	inf->server->RemoveClient(inf->client);
}

unsigned int Server::Start(unsigned short int port, const std::string& address)
{
	if (address == "")
	{
		if (this->_cnt->Init(port) != 0)
			return (1);
	}
	else
	{
		if (this->_cnt->Init(port, address) != 0)
			return (2);
	}
	if (this->_cnt->Listen() != 0)
		return (3);

	ThreadPool::Request *rqt = new ThreadPool::Request();
	rqt->function = &Server::AcceptClient;
	rqt->autoFree = true;
	rqt->parameters = this;
	ThreadPool::GetThreadPool()->AddRequest(rqt);
	/*
	ThreadPool::Request *rqt2 = new ThreadPool::Request();
	rqt2->function = &Server::DisplayOctectInOut;
	rqt2->autoFree = true;
	rqt2->parameters = this;
	ThreadPool::GetThreadPool()->AddRequest(rqt2);
	*/
	return (0);
}

std::list<Client*>*	Server::GetClient()
{
	return &(this->_clientList);
}

IEmpacter*	Server::GetEmpacter()
{
	return this->_emp;
}

void		Server::RemoveClient(Client* client)
{
	this->_mtxClientListModification->Lock();
	this->_clientList.remove(client);
	this->_mtxClientListModification->Unlock();
	delete client;
}

void	Server::AddClient(Client* client)
{
	this->_mtxClientListModification->Lock();
	this->_clientList.push_back(client);
	this->_mtxClientListModification->Unlock();
}

ULONGLONG	getTime()
{
	SYSTEMTIME systemTime;
	FILETIME fileTime;
	ULARGE_INTEGER uli;
	ULONGLONG systemTimeIn_ms;

	GetSystemTime( &systemTime );
	SystemTimeToFileTime( &systemTime, &fileTime );
	uli.LowPart = fileTime.dwLowDateTime; // could use memcpy here!
	uli.HighPart = fileTime.dwHighDateTime;
	systemTimeIn_ms = uli.QuadPart/10000;
	return systemTimeIn_ms;
}

IMutex*	Server::GetMutexClientListBrowse()
{
	return (this->_mtxClientListBrowse);
}

IMutex*	Server::GetMutexClientListModification()
{
	return (this->_mtxClientListModification);
}

void	Server::AccesClientList(bool need)
{
	if (need)
		this->_clientListNbAcces++;
	else
		this->_clientListNbAcces--;
}

bool	Server::ClientListIsAccessed()
{
	if (this->_clientListNbAcces)
		return (true);
	return (false);
}